package com.summer.filesync.network;

import com.summer.filesync.model.Message;
import com.summer.filesync.serialization.SerializationManager;
import com.summer.filesync.util.Logger;
import java.io.*;
import java.net.Socket;
import java.net.SocketTimeoutException;

/** 节点连接 封装单个节点的Socket连接，处理消息的序列化传输 */
public class NodeConnection {

  private static final Logger logger = Logger.getLogger(NodeConnection.class);
  private static final int SOCKET_TIMEOUT = 30000; // 30秒超时

  private String nodeId;
  private Socket socket;
  private DataInputStream dataInputStream;
  private DataOutputStream dataOutputStream;
  private NetworkManager networkManager;
  private long lastHeartbeat;
  private boolean isConnected;

  public NodeConnection(Socket socket, NetworkManager networkManager) throws IOException {
    this.socket = socket;
    this.networkManager = networkManager;
    this.isConnected = true;
    this.lastHeartbeat = System.currentTimeMillis();

    // 设置Socket选项
    socket.setSoTimeout(SOCKET_TIMEOUT);
    socket.setKeepAlive(true);
    socket.setTcpNoDelay(true);

    // 创建数据流
    this.dataOutputStream =
        new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));
    this.dataInputStream = new DataInputStream(new BufferedInputStream(socket.getInputStream()));

    logger.debug("NodeConnection created for: " + socket.getRemoteSocketAddress());
  }

  /** 发送消息 */
  public synchronized void sendMessage(Message message) throws IOException {
    if (!isConnected || socket.isClosed()) {
      throw new IOException("Connection is not available");
    }

    try {
      // 序列化消息
      byte[] messageData = SerializationManager.serialize(message);

      // 发送消息长度
      dataOutputStream.writeInt(messageData.length);

      // 发送消息数据
      dataOutputStream.write(messageData);
      dataOutputStream.flush();

      logger.debug("Sent message: " + message.getType() + " to " + nodeId);

    } catch (IOException e) {
      logger.error("Error sending message to " + nodeId, e);
      handleConnectionError(e);
      throw e;
    }
  }

  /** 接收消息 */
  public Message receiveMessage() throws IOException {
    if (!isConnected || socket.isClosed()) {
      throw new IOException("Connection is not available");
    }

    try {
      // 读取消息长度
      int messageLength = dataInputStream.readInt();

      if (messageLength <= 0 || messageLength > 10 * 1024 * 1024) { // 最大10MB
        throw new IOException("Invalid message length: " + messageLength);
      }

      // 读取消息数据
      byte[] messageData = new byte[messageLength];
      dataInputStream.readFully(messageData);

      // 反序列化消息
      Message message = SerializationManager.deserialize(messageData, Message.class);

      // 更新心跳时间
      updateLastHeartbeat();

      logger.debug("Received message: " + message.getType() + " from " + message.getSourceNodeId());

      return message;

    } catch (SocketTimeoutException e) {
      logger.debug("Socket read timeout for " + nodeId);
      throw e;
    } catch (IOException | ClassNotFoundException e) {
      logger.error("Error receiving message from " + nodeId, e);
      handleConnectionError(e);
      throw new IOException("Failed to receive message", e);
    }
  }

  /** 检查连接是否存活 */
  public boolean isAlive() {
    if (!isConnected || socket.isClosed()) {
      return false;
    }

    // 检查心跳超时
    long now = System.currentTimeMillis();
    long heartbeatTimeout = 60000; // 60秒心跳超时

    if (now - lastHeartbeat > heartbeatTimeout) {
      logger.warn("Heartbeat timeout for node: " + nodeId);
      return false;
    }

    return true;
  }

  /** 更新最后心跳时间 */
  public void updateLastHeartbeat() {
    this.lastHeartbeat = System.currentTimeMillis();
  }

  /** 处理连接错误 */
  private void handleConnectionError(Exception e) {
    if (isConnected) {
      isConnected = false;
      if (nodeId != null && networkManager != null) {
        networkManager.handleConnectionLost(nodeId);
      }
    }
  }

  /** 关闭连接 */
  public void close() {
    if (!isConnected) {
      return;
    }

    isConnected = false;

    try {
      if (dataOutputStream != null) {
        dataOutputStream.close();
      }
    } catch (IOException e) {
      logger.error("Error closing output stream", e);
    }

    try {
      if (dataInputStream != null) {
        dataInputStream.close();
      }
    } catch (IOException e) {
      logger.error("Error closing input stream", e);
    }

    try {
      if (socket != null && !socket.isClosed()) {
        socket.close();
      }
    } catch (IOException e) {
      logger.error("Error closing socket", e);
    }

    logger.debug("NodeConnection closed for: " + nodeId);
  }

  /** 获取远程地址 */
  public String getRemoteAddress() {
    if (socket != null) {
      return socket.getRemoteSocketAddress().toString();
    }
    return "unknown";
  }

  /** 获取连接状态 */
  public boolean isConnected() {
    return isConnected && !socket.isClosed();
  }

  /** 获取最后心跳时间 */
  public long getLastHeartbeat() {
    return lastHeartbeat;
  }

  /** 设置节点ID */
  public void setNodeId(String nodeId) {
    this.nodeId = nodeId;
  }

  /** 获取节点ID */
  public String getNodeId() {
    return nodeId;
  }

  /** 获取Socket信息 */
  public String getSocketInfo() {
    if (socket != null) {
      return "Local: "
          + socket.getLocalSocketAddress()
          + ", Remote: "
          + socket.getRemoteSocketAddress()
          + ", Connected: "
          + !socket.isClosed();
    }
    return "Socket: null";
  }

  @Override
  public String toString() {
    return "NodeConnection{"
        + "nodeId='"
        + nodeId
        + '\''
        + ", connected="
        + isConnected
        + ", lastHeartbeat="
        + lastHeartbeat
        + ", socket="
        + getSocketInfo()
        + '}';
  }
}
